package com.xlh.virtualization.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.xlh.dao.system.SystemConfigMapper;
import com.xlh.enums.LocalResourcesEnum;
import com.xlh.enums.SystemConfigEnum;
import com.xlh.exception.common.GlobalException;
import com.xlh.pojo.system.SystemConfig;
import com.xlh.service.system.SystemConfigService;
import com.xlh.util.InputValidator;
import com.xlh.virtualization.dao.ImageMapper;
import com.xlh.virtualization.dao.ext.ImageMapperExt;
import com.xlh.virtualization.dao.helper.ContainerMapperHelper;
import com.xlh.virtualization.dao.helper.ImageMapperHelper;
import com.xlh.dokka.api.DokkaImageService;
import com.xlh.virtualization.domain.Container;
import com.xlh.virtualization.domain.Image;
import com.xlh.virtualization.domain.ImageAttr;
import com.xlh.virtualization.domain.example.ImageExample;
import com.xlh.virtualization.po.ImageImportPO;
import com.xlh.virtualization.properties.ContainerProperties;
import com.xlh.virtualization.service.ContainerService;
import com.xlh.virtualization.service.ImageService;
import com.xlh.vo.IconVO;
import com.xlh.virtualization.vo.ImageVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.xlh.virtualization.constant.ImageConstant.SYSTEM_PRESET_CODE;

/**
 * @author cheer
 */
@Service
public class ImageServiceImpl implements ImageService {

    @Autowired
    private DokkaImageService dokkaImageService;

    @Autowired
    private ContainerService containerService;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private ContainerProperties containerProperties;

    @Autowired
    private SystemConfigMapper systemConfigMapper;

    @Autowired
    private ImageMapperHelper imageMapperHelper;

    @Autowired
    private ImageMapperExt imageMapperExt;

    @Autowired
    private ImageMapper imageMapper;

    @Autowired
    private ContainerMapperHelper containerMapperHelper;

    @Override
    public void importImage(ImageImportPO imageImportPO) {
        String imageNameInDocker = StringUtils.trimToNull(imageImportPO.getImageNameInDocker());
        if (StringUtils.isBlank(imageNameInDocker)) {
            throw new GlobalException("docker镜像名称不能为空");
        }
        if (StringUtils.length(imageNameInDocker) > 64) {
            throw new GlobalException("docker镜像名称不能超过64个字符");
        }
        if (!InputValidator.isValidInput(imageNameInDocker)) {
            throw new GlobalException(InputValidator.INVALID_INPUT);
        }
        if (imageImportPO.getGpu() == null) {
            throw new GlobalException("gpu选项不能为空");
        }
        String imageName = StringUtils.trimToNull(imageImportPO.getImageName());
        if (imageMapperHelper.isExistsImageName(imageName)) {
            throw new GlobalException("镜像名称已存在");
        }

        Image image = Image.builder()
                .imageName(imageName)
                .icon(imageImportPO.getIcon())
                .description(imageImportPO.getDescription())
                .imageNameInDocker(imageNameInDocker)
                .gpu(imageImportPO.getGpu())
                .imageSource(SYSTEM_PRESET_CODE)
                .shared(true)
                .build();
        imageMapper.insertSelective(image);
    }

    @Override
    public void deleteImage(Long imageId) {
        Image image = imageMapperHelper.getById(imageId);
        if (image == null) {
            throw new GlobalException("镜像不存在");
        }

        List<Container> containers = containerMapperHelper.listContainersByImageId(image.getId());
        if (CollectionUtils.isNotEmpty(containers)) {
            containerService.deleteContainer(containers);
        }

        dokkaImageService.deleteImage(containerProperties.getRegistry() + "/" + image.getImageNameInDocker());

        Image deletedImage = Image.builder()
                .id(imageId)
                .deleted(true)
                .build();
        imageMapper.updateByPrimaryKeySelective(deletedImage);
    }

    @Override
    public void deleteImages(List<Long> imageIds) {
        List<Container> containers = containerMapperHelper.listContainersByImageIds(imageIds);
        if (CollectionUtils.isNotEmpty(containers)) {
            containerService.deleteContainer(containers);
        }

        List<Image> images = imageMapperHelper.listByIds(imageIds);
        if (CollectionUtils.isNotEmpty(images)) {
            for (Image image : images) {
                dokkaImageService.deleteImage(containerProperties.getRegistry() + "/" + image.getImageNameInDocker());
            }
            imageMapperHelper.deleteByIds(imageIds);
        }
    }

    @Override
    public void deleteImageByContext(Integer contextType, Long contextId) {
        List<Image> images = imageMapperHelper.listByContext(contextType, contextId);
        if (CollectionUtils.isEmpty(images)) {
            return;
        }

        List<Long> imageIds = images.stream().map(Image::getId).collect(Collectors.toList());
        List<Container> containers = containerMapperHelper.listContainersByImageIds(imageIds);
        if (CollectionUtils.isNotEmpty(containers)) {
            containerService.deleteContainer(containers);
        }

        for (Image image : images) {
            dokkaImageService.deleteImage(containerProperties.getRegistry() + "/" + image.getImageNameInDocker());
        }

        imageMapperHelper.deleteByIds(imageIds);
    }

    @Override
    public void updateImage(Long imageId, ImageImportPO imageImportPO, Boolean isSuperAdmin) {
        String imageNameInDocker = StringUtils.trimToNull(imageImportPO.getImageNameInDocker());
        if (isSuperAdmin) {
            if (StringUtils.isBlank(imageNameInDocker)) {
                throw new GlobalException("docker镜像名称不能为空");
            }
            if (imageImportPO.getGpu() == null) {
                throw new GlobalException("gpu选项不能为空");
            }
        }
        Image image = imageMapperHelper.getById(imageId);
        if (image == null) {
            throw new GlobalException("镜像不存在");
        }
        String imageName = StringUtils.trimToNull(imageImportPO.getImageName());
        if (!StringUtils.equals(image.getImageName(), imageName) && imageMapperHelper.isExistsImageName(imageName)) {
            throw new GlobalException("镜像名称已存在");
        }

        Image updateImage = Image.builder()
                .id(imageId)
                .imageName(imageName)
                .icon(imageImportPO.getIcon())
                .description(imageImportPO.getDescription())
                .imageNameInDocker(isSuperAdmin ? imageNameInDocker : null)
                .gpu(isSuperAdmin ? imageImportPO.getGpu() : null)
                .build();
        imageMapper.updateByPrimaryKeySelective(updateImage);
    }

    @Override
    public ImageVO getImageById(Long imageId, Boolean isSuperAdmin) {
        Image image = imageMapperHelper.getById(imageId);
        if (image == null) {
            return null;
        }

        ImageVO imageVO = ImageVO.builder()
                .imageId(image.getId())
                .imageName(image.getImageName())
                .imageNameInDocker(isSuperAdmin ? image.getImageNameInDocker() : null)
                .icon(image.getIcon())
                .description(image.getDescription())
                .gpu(image.getGpu())
                .build();

        SystemConfig systemConfig = systemConfigMapper.selectByPrimaryKey(image.getIcon());
        if (systemConfig != null) {
            imageVO.setIconUrl(LocalResourcesEnum.SYSTEM_FILE.getMappingUrl(systemConfig.getKeyValue()));
        }

        return imageVO;
    }

    @Override
    public List<IconVO> listImageIcons() {
        List<SystemConfig> systemConfigs = systemConfigService.listConfigByKeys(
                Lists.newArrayList(SystemConfigEnum.IMAGE_ICON.getKey()));
        List<IconVO> iconVOS = new ArrayList<>();
        for (SystemConfig systemConfig : systemConfigs) {
            IconVO iconVO = IconVO.builder()
                    .icon(systemConfig.getId())
                    .iconUrl(SystemConfigEnum.IMAGE_ICON.getMappingUrl(systemConfig.getKeyValue()))
                    .build();
            iconVOS.add(iconVO);
        }
        return iconVOS;
    }

    @Override
    public List<Image> listImages(List<Long> imageIds) {
        return imageMapperHelper.listByIds(imageIds);
    }

    @Override
    public PageInfo<ImageAttr> listSharedImagesByPage(Integer pageNum, Integer pageSize, Long imageSource) {
        PageHelper.startPage(pageNum, pageSize);
        List<ImageAttr> imageAttrs = imageMapperExt.listSharedImages(imageSource);
        return new PageInfo<>(imageAttrs);
    }

    @Override
    public List<ImageAttr> listImagesByCourseId(Long courseId) {
        return imageMapperExt.listImagesByCourseId(courseId);
    }

    @Override
    public void updateSharedStatusByContext(Integer contextType, Long contextId, Boolean shared) {
        imageMapperHelper.updateSharedStatusByContext(contextType, contextId, shared);
    }

    @Override
    public void check() {
        ImageExample example = new ImageExample();
        example.or().andDeletedEqualTo(false);
        List<Image> images = imageMapper.selectByExample(example);

        List<String> error = new ArrayList<>();

        for (Image image : images) {
            List<String> hostList = dokkaImageService.inspectImage(
                    containerProperties.getRegistry() + "/" + image.getImageNameInDocker());
            if (CollectionUtils.isNotEmpty(hostList)) {
                error.add("主机" + StringUtils.join(hostList, ",")+"缺少镜像"+image.getImageNameInDocker());
            }
        }

        if(CollectionUtils.isNotEmpty(error)){
            throw new GlobalException(StringUtils.join(error, ";"));
        }
    }
}
